package store.lunangangster.engine.impl.calendar;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import org.joda.time.DateTime;
import org.joda.time.Period;
import store.lunangangster.engine.EngineClock;
import store.lunangangster.engine.NodeFlowException;

/**
 * 用于ISO Duration格式的时间解析
 *
 * @author cwk
 * @version 1.0
 */
public class DurationParser {

  protected String durationString;
  protected DateTime startTime;
  protected DateTime endTime;
  protected boolean isRepeat;
  protected int repeatTimes;    // 需要重复的次数
  protected int times;          // 当前重复次数
  protected boolean isPeriod;
  protected Period period;

  protected EngineClock engineClock;

  public DurationParser(String durationString, EngineClock engineClock) {
    this.durationString = durationString;
    this.engineClock = engineClock;
    startTime = null;
    endTime = null;
    this.repeatTimes = -1;
    this.times = 0;
    this.period = Period.ZERO;
    parse();
  }

  private void parse() {
    // example: R3/20040506T130000+08/P0Y6M5DT3H0M0S
    // 重复次数/开始时间/重复周期
    List<String> items = Arrays.asList(durationString.split("/"));
    if (items.size() > 3 || items.size() < 0) {
      throw new NodeFlowException("错误的Duration时间格式: " + durationString);
    }
    int indexNow = 0;
    if (isRepeat(items.get(indexNow))) { // R开头
      isRepeat = true;
      repeatTimes = items.get(indexNow).length() == 1 ? -1 : Integer.parseInt(items.get(indexNow).substring(1));
      indexNow ++;
    }
    if (isPeriod(items.get(indexNow))) {  // P开头
      period = Period.parse(items.get(indexNow));
      isPeriod = true;
    } else {
      startTime = DateTime.parse(items.get(indexNow));
      indexNow ++;
      if (indexNow < items.size() && isPeriod(items.get(indexNow))) {
        period = Period.parse(items.get(indexNow));
        isPeriod = true;
      } else {
        endTime = DateTime.parse(items.get(indexNow));
      }
    }

    if (startTime == null) {
      startTime = new DateTime(engineClock.now());
    }
  }

  public Date getNextDate() {
    return getNextDate(engineClock).toDate();
  }

  private DateTime getNextDate(EngineClock engineClock) {
    Date now = engineClock.now();
    if (isRepeat) {
      return getNextDateAfterRepeat(now);
    }
    if (endTime != null) {
      return endTime;
    }
    return add(startTime, period);
  }

  private DateTime getNextDateAfterRepeat(Date date) {
    DateTime current = startTime;
    DateTime bound = new DateTime(date);
    if (repeatTimes < 0) { // no bound
      DateTime newDateTime;
      while (!current.isAfter(bound)) {
        newDateTime = current.plus(period);
        if (!newDateTime.isAfter(current)) {
          break;
        }
        current = newDateTime;
      }
    } else {
      for (int i = times + 1; i <= repeatTimes && !current.isAfter(bound); i++) {
          current = current.plus(period);
      }
    }

    // 如果循环完之后，current还小于bound，说明已经超过了循环次数
    return current.isBefore(bound) ? bound : current;
  }

  DateTime add(DateTime time, Period period) {
    return time.plus(period);
  }


  private static boolean isRepeat(String item) {
    return Optional.ofNullable(item).map(s -> s.length() > 0 && s.charAt(0) == 'R').orElse(false);
  }

  private static boolean isPeriod(String item) {
    return Optional.ofNullable(item).map(s -> s.length() > 0 && s.charAt(0) == 'P').orElse(false);
  }

}
